package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
	"sync"
)

var cnum chan int
var failedCount = 0
var lock = &sync.Mutex{}

var strTable = map[string]string{
	"_z2C$q": ":",
	"_z&e3B": ".",
	"AzdH3F": "/",
}

var charTable = map[string]string{
	"w": "a",
	"k": "b",
	"v": "c",
	"1": "d",
	"j": "e",
	"u": "f",
	"2": "g",
	"i": "h",
	"t": "i",
	"3": "j",
	"h": "k",
	"s": "l",
	"4": "m",
	"g": "n",
	"5": "o",
	"r": "p",
	"q": "q",
	"6": "r",
	"f": "s",
	"p": "t",
	"7": "u",
	"e": "v",
	"o": "w",
	"8": "1",
	"d": "2",
	"n": "3",
	"9": "4",
	"c": "5",
	"m": "6",
	"0": "7",
	"b": "8",
	"l": "9",
	"a": "0",
}

func main() {
	fmt.Println("")
	fmt.Println("*****  百度图片爬取工具（高像素） *****")
	fmt.Println("提示：")
	fmt.Println("  1、下载速度皆与客户端硬件和网速有关。")
	fmt.Println("  2、下载过程中出现卡顿，请耐心等待。")
	fmt.Println("  3、下载过程中报错即视为数据请求失败。")
	fmt.Println("***************************************")
	fmt.Println("")
	baidu()
}

func baidu() {
	choose := bufio.NewScanner(os.Stdin)

	fmt.Println("")
	fmt.Println("请输入搜索内容，回车搜索：")

	choose.Scan()
	encryption := choose.Text()
	//数据编码
	input := url.QueryEscape(encryption)

	baseURL := "http://image.baidu.com/search/acjson?tn=resultjson_com&ipn=rj&ct=201326592&fp=result&cl=2&lm=-1&ie=utf-8&oe=utf-8&st=-1&ic=0&face=0&istype=2nc=1&rn=60&word=" + input + "&pn="

	var total = 0

	for i := 0; ; i++ {
		rn := 60
		pn := rn*i + 1
		reqURL := baseURL + strconv.Itoa(pn)
		resp, err := http.Get(reqURL)
		if err != nil {
			fmt.Println("error ")
			fmt.Println(err.Error())
			return
		}
		defer resp.Body.Close()
		content, _ := ioutil.ReadAll(resp.Body)
		reg := regexp.MustCompile("\"objURL\":\"(.*?)\"")
		var imgList = reg.FindAllString(string(content), -1)
		if len(imgList) == 0 {
			fmt.Println("no data ")
			break
		}
		cnum = make(chan int, len(imgList))
		for _, img := range imgList {
			total++
			img = img[10 : len(img)-1]
			img = buildURL(img)
			fmt.Println("-------------------------------------")
			fmt.Println("开始获取第", total, "张", encryption, "图片，下载地址为：", img)
			ttl := strconv.Itoa(total)
			downloader(encryption, ttl, img)
		}
		for i := 0; i < len(imgList); i++ {
			<-cnum
		}
	}

}

//对数据信息进行解析
func buildURL(orginalURL string) string {
	for k, v := range strTable {
		orginalURL = strings.Replace(orginalURL, k, v, -1)
	}
	var newURL = ""
	for _, v := range orginalURL {
		v1 := string(v)
		v2, succ := charTable[v1]
		if succ {
			v1 = v2
		}
		newURL = newURL + v1
	}
	return newURL
}

//下载器
func downloader(name string, total string, url string) {
	ext := ".jpg"
	directory := "Images"
	folderPath := filepath.Join(name)
	if _, err := os.Stat(directory); os.IsNotExist(err) {
		// 必须分成两步
		// 先创建文件夹
		os.Mkdir("./"+directory, 0777)
		// 再修改权限
		os.Chmod("./"+directory, 0777)
	}
	if _, err := os.Stat(folderPath); os.IsNotExist(err) {
		// 先创建文件夹
		os.Mkdir("./"+directory+"/"+folderPath, 0777)
		// 再修改权限
		os.Chmod("./"+directory+"/"+folderPath, 0777)
	}

	// 文件头识别后缀_0
	var headerByte []byte
	headerByte = make([]byte, 8)
	rr, err := http.Get(url)
	headerByteTemp := rr.Body
	headerByteTemp.Read(headerByte)
	//ext, _ = GetImgExtLocal(headerByte)

	// 获取图片数据流
	r, err := http.Get(url)
	defer func() {
		if r != nil && r.Body != nil && !r.Close {
			r.Body.Close()
		}
		cnum <- 1
	}()
	if err != nil || r.StatusCode != 200 {
		fmt.Println("下载失败啦：" + url)
		lock.Lock()
		failedCount++
		lock.Unlock()
		return
	}
	body, _ := ioutil.ReadAll(r.Body)

	// 文件头识别后缀_1
	//ext, _ = GetImgExt(url)
	// 文件头识别后缀_2
	// 本地文件
	//f, err := os.Open("C:\\Users\\Administrator\\Desktop\\api.html")
	//f, err := os.Open(url)
	//if err == nil {
	//	// 本地文件
	//	fSrc, err := ioutil.ReadAll(f)
	//	fmt.Println(GetFileType(fSrc[:10]))
	//	fmt.Println("open error: %v", err)
	//}else {
	//	// 网络文件： 前面8个字节即可判断
	//	var headerByte []byte
	//	headerByte = make([]byte, 10)
	//	r, _ := http.Get(url)
	//	defer func() {
	//		if r != nil && r.Body != nil && !r.Close {
	//			r.Body.Close()
	//		}
	//		cnum <- 1
	//	}()
	//	r.Body.Read(headerByte)
	//	ext = GetFileType(headerByte)
	//}

	// 将图片下载到指定文件夹
	//out, _ := os.Create(fmt.Sprintf("./" + directory + "/" + name + "/" + total + ".jpg"))
	out, _ := os.Create(fmt.Sprintf("./" + directory + "/" + name + "/" + total + ext))
	io.Copy(out, bytes.NewReader(body))
}
